﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using Framework.ObjectPool;
using System.Reflection;

namespace Framework.ObjectFactory
{
    internal abstract class PoolClassBuilderBase<TType> : ClassBuilderBase<TType>, ITypeBuilder where TType : class
    {
        public PoolClassBuilderBase(Type baseClassType)
            : base(baseClassType)
        {
        }

        /// <summary>
        /// 生成类中方法的实现
        /// </summary>
        /// <param name="builder"></param>
        protected override void GenerateMethodImpl(TypeBuilder builder)
        {
            GenerateIPoolInstanceImpl(builder);
        }

        /// <summary>
        /// 生成IPoolInstance接口的实现
        /// </summary>
        /// <param name="builder"></param>
        private void GenerateIPoolInstanceImpl(TypeBuilder builder)
        {
            Type currentType = typeof(IPoolInstance);
            // 创建Status属性
            FieldBuilder fieldStatusBuilder = builder.DefineField("status", typeof(PoolInstanceStatus), FieldAttributes.Private);
            fieldStatusBuilder.SetConstant(0);
            PropertyBuilder propertyStatusBuilder = builder.DefineProperty("Status", PropertyAttributes.None, typeof(PoolInstanceStatus), null);

            MethodInfo[] methods = currentType.GetMethods();
            foreach (MethodInfo method in methods)
            {
                Type[] parameterTypes = GetParameters(method.GetParameters());
                MethodBuilder methodBuilder = builder.DefineMethod(method.Name, defaultMethodAttributes, method.ReturnType, parameterTypes);

                methodBuilder.CreateMethodBody(null, 0);
                ILGenerator iLGenerator = methodBuilder.GetILGenerator();

                if (method.Name == "get_Status")
                {
                    iLGenerator.Emit(OpCodes.Ldarg_0);
                    iLGenerator.Emit(OpCodes.Ldfld, fieldStatusBuilder);
                    iLGenerator.Emit(OpCodes.Ret);
                    propertyStatusBuilder.SetGetMethod(methodBuilder);
                }
                else if (method.Name == "set_Status")
                {
                    iLGenerator.Emit(OpCodes.Ldarg_0);
                    iLGenerator.Emit(OpCodes.Ldarg_1);
                    iLGenerator.Emit(OpCodes.Stfld, fieldStatusBuilder);
                    iLGenerator.Emit(OpCodes.Ret);
                    propertyStatusBuilder.SetSetMethod(methodBuilder);
                }

                builder.DefineMethodOverride(methodBuilder, method);
            }

            // 实现Dispose方法
            MethodInfo methodDispose = typeof(IDisposable).GetMethod("Dispose");
            MethodBuilder methodBuilderDispose = builder.DefineMethod(methodDispose.Name, defaultMethodAttributes, methodDispose.ReturnType, null);
            methodBuilderDispose.CreateMethodBody(null, 0);
            ILGenerator iLGeneratorDispose = methodBuilderDispose.GetILGenerator();
            iLGeneratorDispose.Emit(OpCodes.Ldarg_0);
            iLGeneratorDispose.Emit(OpCodes.Ldc_I4_1);
            iLGeneratorDispose.Emit(OpCodes.Call, propertyStatusBuilder.GetSetMethod());
            iLGeneratorDispose.Emit(OpCodes.Ret);
            builder.DefineMethodOverride(methodBuilderDispose, methodDispose);
        }

        /// <summary>
        /// 生成类型
        /// </summary>
        /// <returns></returns>
        protected override Type GenerateTypeImplementation()
        {
            TypeBuilder builder;
            try
            {
                builder = moduleBuilder.DefineType(generatedAssemblyName + "." + generatedClassName, TypeAttributes.Public, baseClassType,
                        new Type[] { typeof(IPoolInstance) });
            }
            catch (Exception ex)
            {
                throw new Exception("未能定义类型 " + generatedClassName + " : " + baseClassType + " , " + typeof(IPoolInstance).Name, ex);
            }
            if (builder == null)
            {
                throw new Exception("未能定义类型 " + generatedClassName + " : " + baseClassType + " , " + typeof(IPoolInstance).Name);
            }

            GenerateConstructor(builder);
            GenerateMethodImpl(builder);

            try
            {
                Type generatedType = builder.CreateType();
                return generatedType;
            }
            catch (Exception ex)
            {
                throw new Exception("未能创建类型 " + generatedClassName + " : " + baseClassType + " , " + typeof(IPoolInstance).Name, ex);
            }
        }
    }
}
